package jdklearning.ref;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RefQueueAndWatchLearning {
	
	Set<String> retainedKeys = Collections.synchronizedSet(new HashSet<String>());
	ReferenceQueue<Object> queue = new ReferenceQueue<>();
	ExecutorService es = Executors.newFixedThreadPool(1);
	
	
	public static void main(String[] args) {
		while(true) {
			
		}
	}
	
	
	final class KeyedWeakReference extends WeakReference<Object> {
		  public final String key;
		  public final String name;

		  KeyedWeakReference(Object referent, String key, String name,
		      ReferenceQueue<Object> referenceQueue) {
		    super(referent, referenceQueue);
		    this.key = key;
		    this.name = name;
		  }
	}
	
	
	
	public void watch(Object watchedReference) {
	   watch(watchedReference, "");
	}

		/**
		 * Watches the provided references and checks if it can be GCed. This method is non blocking,
		 * the check is done on the {@link WatchExecutor} this {@link RefWatcher} has been constructed
		 * with.
		 *
		 * @param referenceName An logical identifier for the watched object.
		 */
		public void watch(Object watchedReference, String referenceName) {
//		  if (this == DISABLED) {
//		    return;
//		  }
		  
		  final long watchStartNanoTime = System.nanoTime();
		  // 保证 key 的唯一性
		  String key = UUID.randomUUID().toString();
		  // 添加到 set 集合中
		  retainedKeys.add(key);
		  // 穿件 KeyedWeakReference 对象
		  final KeyedWeakReference reference =
		      new KeyedWeakReference(watchedReference, key, referenceName, queue);

		  ensureGoneAsync(watchStartNanoTime, reference);
		}

		
		
		private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
			es.execute(new Runnable() {
				@Override
				public void run() {
					ensureGone(reference, watchStartNanoTime);
				}
			});
		}
			
		
		private boolean gone(KeyedWeakReference reference) {
		  return !retainedKeys.contains(reference.key);
		}
		
		void ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
			  long gcStartNanoTime = System.nanoTime();
//			  long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);

			   // 移除已经被回收的引用
			  removeWeaklyReachableReferences();

			  // 判断 reference，即 activity 是否内回收了，若被回收了，直接返回
			  if (gone(reference)) {
			    return ;
			  }
			  // 调用 gc 方法进行垃圾回收
			  System.gc();
			   // 移除已经被回收的引用
			  removeWeaklyReachableReferences();
			  // activity 还没有被回收，证明发生内存泄露
			  if (!gone(reference)) {
			    long startDumpHeap = System.nanoTime();
//			    long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
			  }
		}

		
		
		private void removeWeaklyReachableReferences() {
			  // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
			  // reachable. This is before finalization or garbage collection has actually happened.
			  KeyedWeakReference ref;
			  // 遍历 queue ，并从 retainedKeys set 集合中移除
			  while ((ref = (KeyedWeakReference) queue.poll()) != null) {
			    retainedKeys.remove(ref.key);
			  }
		}




}
